﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Text;
using KAImage.Algorithms;

namespace KAImage
{
    /// <summary>
    /// 色阶
    /// </summary>
    public class ImageLevels
    {
        private readonly int nShadow = 0;      
        private readonly int nHighLight = 255;

        private double dMidtone = 1.0D;
        public double Midtone
        {
            get 
            { 
                return dMidtone; 
            }
            set
            {
                if (dMidtone != value)
                {
                    _isDefault = false;
                    _bUpdated = true;
                    dMidtone = value;
                }
            }
        }

        private int[] Mapping = new int[256];

        /// <summary>
        /// 颜色通道
        /// </summary>
        private ColorChannel _channel = ColorChannel.RGB;
        public ColorChannel Channel
        {
            get { return _channel; }
            set { _channel = value; }
        }

        public ImageLevels()
        {
            Reset();
        }

        public ImageLevels(ColorChannel ch)
        {
            _channel = ch;
            Reset();
        }

        /// <summary>
        /// 指示色阶是否是默认值
        /// </summary>
        private bool _isDefault = true;
        public bool IsDefault
        {
            get { return _isDefault; }
        }

        /// <summary>
        /// 指示色阶命令参数是否需要重新映射(计算)
        /// </summary>
        private bool _bUpdated = false;
        public bool IsUpdated
        {
            get { return _bUpdated; }
        }
       
        private void Reset()
        {
            Array.Clear(Mapping, 0, 256);
            for (int i = 0; i < Mapping.Length; i++)
            {
                Mapping[i] = i;
            }
        }

        private void GetLevelTable()
        {           
            if (dMidtone > 9.99) dMidtone = 9.99;
            if (dMidtone < 0.10) dMidtone = 0.10;

            double dDiff = nHighLight - nShadow;

            for (int Index = 0; Index <= 255; Index++)
            {
                double Temp = Index - nShadow;
                if (Temp < 0)
                {
                    Temp = nShadow;
                }
                else if (Temp + nShadow > nHighLight)
                {
                    Temp = nHighLight;
                }
                else
                {
                    Temp = Math.Pow((Temp / dDiff), 1 / dMidtone) * 255;                 
                }
                if (Temp > 255)
                    Temp = 255;
                else if (Temp < 0)
                    Temp = 0;
                Mapping[Index] = (int)Math.Round(Temp,0);
            }
        }

        private void ApplyMapping(Bitmap source)
        {
            switch (_channel)
            {
                case ColorChannel.RGB:
                    ImageAdjustments.ApplyMappingToRGB(source, Mapping);
                    break;
                case ColorChannel.R:
                    ImageAdjustments.ApplyMappingToR(source, Mapping);
                    break;
                case ColorChannel.G:
                    ImageAdjustments.ApplyMappingToG(source, Mapping);
                    break;
                case ColorChannel.B:
                    ImageAdjustments.ApplyMappingToB(source, Mapping);
                    break;
                default:
                    break;
            }
        }

        public void Adjust(Bitmap source)
        {
            if (_bUpdated)
            {
                Reset();             
                GetLevelTable();
            }
            ApplyMapping(source);
            _bUpdated = false;
        }
    }
}
